﻿using System.Runtime.InteropServices;

using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http;

using Tszy.Unlimited.Base.Exceptions;
using Tszy.Unlimited.Base.Infrastructure.Logging;
using Tszy.Unlimited.Base.Json;
using Tszy.Unlimited.Base.Models;

namespace Tszy.Unlimited.AspNetCore.Filters;

public class RequestCoreFilter
{
    private readonly RequestDelegate _next;

    /// <summary>
    /// 初始化请求处理器。
    /// </summary>
    /// <param name="next"></param>
    public RequestCoreFilter(RequestDelegate next)
    {
        _next = next;
    }

    /// <summary>
    /// 请求处理。
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public async Task Invoke(HttpContext context)
    {
        try
        {
            OnHandle(context);

            await _next(context);
        }
        catch (MainApplicationException exception)
        {
            await HandleExceptionAsync(context, exception.ErrorCode, exception.Message, exception);
        }
        catch (ConnectionResetException exception)
        {
            await HandleExceptionAsync(context, 0, exception.Message, exception);
        }
        catch (COMException exception)
        {
            await HandleExceptionAsync(context, 0, exception.Message, exception);
        }
        catch (Exception exception)
        {
            TszyLogger.Instance.Fatal(exception.Message, exception);
            await HandleExceptionAsync(context, 0, exception.Message, exception);
        }
        finally
        {
            var statusCode = context.Response.StatusCode;

            if (statusCode > 200 && statusCode != 302)
            {
                switch (statusCode)
                {
                    case 400:
                        await HandleExceptionAsync(context, 400, "400 Bad Request");
                        break;

                    case 401:
                        await HandleExceptionAsync(context, 401, "401 Unauthorized");
                        break;

                    case 402:
                        await HandleExceptionAsync(context, 402, "402 Payment Required");
                        break;

                    case 403:
                        await HandleExceptionAsync(context, 403, "403 Forbidden");
                        break;

                    default:
                        break;
                }
            }
        }
    }

    private static async Task HandleExceptionAsync(HttpContext context, int errorCode, string errorMessage, Exception? _ = null)
    {
        errorMessage ??= string.Empty;
        var data = ResponseResult.Error(errorMessage, errorCode);

        await OnHandleExceptionAsync(context, data);
    }

    private static async Task OnHandleExceptionAsync(HttpContext context, object value)
    {
        var data = JsonManager.Serialize(value);

        context.Response.ContentType = "application/json; charset=utf-8";
        context.Response.ContentLength = data.Length;

        await context.Response.WriteAsync(data).ConfigureAwait(false);
    }

    protected virtual void OnHandle(HttpContext context)
    {
    }
}